package org.emavaj.sanguosha.controller.client;

import static org.emavaj.sanguosha.model.constants.Constants.AUDIO_GAME_BACK;

import java.util.List;

import org.apache.log4j.Logger;
import org.emavaj.common.AudioUtil;
import org.emavaj.sanguosha.controller.UDPController;
import org.emavaj.sanguosha.model.card.AbstractCard;
import org.emavaj.sanguosha.model.card.character.Character;
import org.emavaj.sanguosha.model.card.equipment.AbstractEquipmentCard;
import org.emavaj.sanguosha.model.card.resource.CardResHelper;
import org.emavaj.sanguosha.model.constants.Opercation;
import org.emavaj.sanguosha.model.player.Phase;
import org.emavaj.sanguosha.model.player.Player;
import org.emavaj.sanguosha.model.player.Role;
import org.emavaj.sanguosha.model.vo.CardVO;
import org.emavaj.sanguosha.model.vo.CharacterVO;
import org.emavaj.sanguosha.model.vo.SGSPacket;
import org.emavaj.sanguosha.view.MainFrame;
import org.emavaj.sanguosha.view.dialog.ChooseCharacterDialog;
import org.emavaj.sanguosha.view.gameview.GameFrame;
import org.emavaj.sanguosha.view.gameview.OtherPlayerPane;

/**
 * User: DIZEM Time: 11-4-6 下午1:40
 * 
 * eMavaj updated 20120914
 */
public class GameClient extends UDPController {

	private static Logger log = Logger.getLogger(GameClient.class);

	/**
	 * 服务器地址
	 */
	private String serverAddress;
	/**
	 * 服务器端口
	 */
	private int serverPort;
	/**
	 * 玩家姓名
	 */
	private String name;
	/**
	 * 消息接收监控
	 */
	private GameClientMonitor clientMonitor;
	/**
	 * 游戏界面
	 */
	private GameFrame owner;
	/**
	 * 玩家数
	 */
	private int playerCount;
	/**
	 * 主公id
	 */
	private int lordId;
	/**
	 * 当前玩家id
	 */
	private int playerId;
	/**
	 * 玩家列表
	 */
	public Player[] players;

	/**
	 * 构造函数
	 * 
	 * @param serverPort
	 *            服务器端口
	 * @param serverAddress
	 *            服务器地址
	 * @param name
	 *            玩家姓名
	 */
	public GameClient(String serverAddress, int serverPort, String name) {
		this.serverPort = serverPort;
		this.serverAddress = serverAddress;
		this.name = name;
		// 客戶端鏡像
		clientMonitor = new GameClientMonitor(this);
		clientMonitor.start();
		connect();
	}

	/**
	 * 连接服务器
	 */
	public void connect() {
		// 等待创建监控连接
		while (!clientMonitor.isReady()) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				log.error(e.getMessage());
			}
		}
		// 发送连接消息
		send(new SGSPacket(Opercation.OP_CONNECT, name, clientMonitor.getClientPort()));
	}

	/**
	 * 
	 * 显示游戏窗体 -> OP_INIT_CLIENT
	 * 
	 * @param packet
	 */
	public void showGameFrame(SGSPacket packet) {
		playerCount = packet.getPlayerCount();
		// get card info res
		CardResHelper.convertFromCode(packet.getMessage());
		// 初始化游戏界面
		owner = new GameFrame(MainFrame.instance, this, name);
		owner.setCurrentPlayerID(packet.getPlayerId());
	}

	/**
	 * 添加玩家 -> OP_UPDATE_PLAYERS
	 * 
	 * @param packet
	 */
	public void updatePlayers(SGSPacket packet) {

		AudioUtil.play("system/add-player.mp3");
		owner.updatePlayers(packet.getPlayers());
	}

	/**
	 * 发送消息给指定玩家 id = -1表示发送给所有人
	 * 
	 * @param message
	 *            消息
	 * @param toId
	 *            目标玩家id
	 */
	public void sendMessage(String message, int toId) {
		SGSPacket packet = new SGSPacket(Opercation.OP_SEND_CHAT_MESSAGE);
		packet.setMessage(message);
		packet.setMessageToID(toId);
		packet.setPlayerId(owner.getCurrentPlayerID());
		send(packet);
	}

	/**
	 * 发送数据包给服务器
	 * 
	 * @param packet
	 */
	public void send(SGSPacket packet) {
		send(packet, serverAddress, serverPort);
	}

	public String getServerAddress() {
		return serverAddress;
	}

	public int getServerPort() {
		return serverPort;
	}

	public String getName() {
		return name;
	}

	public int getPlayerCount() {
		return playerCount;
	}

	public int getLordId() {
		return lordId;
	}

	public void setLordId(int lordId) {
		this.lordId = lordId;
	}

	/**
	 * 接收并显示系统消息 -> OP_SEND_MESSAGE
	 * 
	 * @param message
	 */
	public void showMessage(String message) {
		owner.appendLog(message);
	}

	/**
	 * 接收并显示聊天信息 -> OP_SEND_CHAT_MESSAGE
	 * 
	 * @param message
	 */
	public void showChatMessage(String message) {
		owner.appendChatMessage(message);
	}

	/**
	 * 设置随即分配下来的身份，同时知道主公的ID -> OP_DISTRIBUTE_ROLE
	 * 
	 * @param role
	 * @param lordId
	 */
	public void setRole(Role role, int lordId) {
		owner.setRole(role, lordId);
	}

	/**
	 * 选择主公武将 -> OP_DISTRIBUTE_LORD_CHARACTER
	 * 
	 * @param packet
	 */
	public void distributeLordCharacter(SGSPacket packet) {
		AudioUtil.play(AUDIO_GAME_BACK);
		lordId = packet.getLordId();
		// 如果自己是主公则选择武将，如果不是则等待别人选择
		if (lordId == owner.getCurrentPlayerID()) {

			Character[] characters = new Character[5];
			for (int i = 0; i < 5; ++i) {
				// 从VO提取数据
				characters[i] = new Character(packet.getCharacterVOs()[i]);
			}

			new ChooseCharacterDialog(owner, characters);

		} else {
			owner.showMessage("等待主公选择武将");
		}
	}

	/**
	 * 主公选择武将结束
	 */
	public void chooseLordCharacterFinish() {
		SGSPacket packet = new SGSPacket(Opercation.OP_FINISH_CHOOSING_LORD_CHARACTER);
		packet.setCharacterVO(new CharacterVO(owner.getPlayers()[owner
				.getCurrentPlayerID()].getCharacter()));
		send(packet);
	}

	/**
	 * 分配其他玩家武将 -> OP_DISTRIBUTE_CHARACTER
	 * 
	 * @param packet
	 */
	public void distributeCharacter(SGSPacket packet) {
		owner.showMessage("主公选择了武将:" + packet.getCharacterVO().getName());
		Character ch = new Character(packet.getCharacterVO());
		owner.setCharacter(lordId, ch);
		
		// 从VO提取信息
		Character[] characters = new Character[3];
		for (int i = 0; i < 3; ++i) {
			characters[i] = new Character(packet.getCharacterVOs()[i]);
		}

		new ChooseCharacterDialog(owner, characters);
	}

	/**
	 * 分配其他玩家武将角色结束
	 */
	public void chooseCharacterFinish() {
		SGSPacket packet = new SGSPacket(Opercation.OP_FINISH_CHOOSING_CHARACTER);
		packet.setPlayerId(playerId);
		packet.setCharacterVO(new CharacterVO(owner.getPlayers()[owner
				.getCurrentPlayerID()].getCharacter()));
		send(packet);
	}

	/**
	 * 发牌 -> OP_DISTRIBUTE_CARD
	 * @param packet
	 */
	public void distributeCards(SGSPacket packet) {
		AbstractCard[] cards = new AbstractCard[packet.getCardVOs().length];

		for (int i = 0; i < packet.getCardVOs().length; ++i) {
//			cards[i] = AbstractCard.createCard(packet.getCardVOs()[i]);
			cards[i] = packet.getCardVOs()[i].toCard();
			// 更新玩家手上的牌
			players[playerId].addHandCard(cards[i]);
		}
		// 更新窗口中的牌
		owner.distributeCards(cards);
	}

	public void setPlayerId(int currentPlayerID) {
		this.playerId = currentPlayerID;
	}

	/**
	 * 选择角色完毕时，设置角色 -> OP_FINISH_CHOOSING_CHARACTER
	 * @param packet
	 */
	public void setCharacter(SGSPacket packet) {
		owner.setCharacter(packet.getPlayerId(),
				new Character(packet.getCharacterVO()));
	}

	/**
	 * 更新玩家信息 -> OP_UPDATE_PLAYERS_INFO
	 * @param packet
	 */
	public void updatePlayersInfo(SGSPacket packet) {
		owner.showMessage(packet.getMessage());
		owner.setOtherPlayerInfo(packet.getPlayerId(), packet.getHandCardCount());
	}

	/**
	 * 开始阶段 -> OP_PHASE_START
	 */
	public void startPhase(int id) {
		// 显示当前处于出牌阶段的玩家昵称
		owner.showMessage(getPlayerName(id) + "进入开始阶段");
		// 更新本地的玩家信息
		players[playerId].setPhase(Phase.START);
		// 判断该玩家是否是自己
		if (id != playerId) {
			// players[id].setPhase(Phase.START);
			// 更新游戏面板状态
			owner.getOtherPlayerPaneList()
					.get(owner.getIndex(playerId)).repaint();
		}
	}

	/**
	 * 判定阶段 -> OP_PHASE_JUDGE_BEGIN
	 */
	public void judgePhase(int id) {
		owner.showMessage(getPlayerName(id) + "进入判定阶段");

		players[id].setPhase(Phase.JUDGE);
		if (id != playerId) {
			owner.getOtherPlayerPaneList()
					.get(owner.getIndex(playerId)).repaint();
		} else {
			SGSPacket packet = new SGSPacket(Opercation.OP_PHASE_JUDGE_END);
			if (players[id].getEffectCards().size() == 0) {
				log.info("没有判定牌，跳过判定阶段");
				send(packet);
			}
		}
	}

	/**
	 * 摸牌阶段 -> OP_PHASE_DRAW_BEGIN
	 * 
	 * @param packet
	 *            数据包
	 */
	public void drawPhase(SGSPacket packet) {
		// 获得玩家ID
		int id = packet.getPlayerId();
		// 更新该玩家的阶段
		players[id].setPhase(Phase.DRAW);
		// 游戏日志
		owner.showMessage(getPlayerName(id) + "进入摸牌阶段");
		owner.showMessage(getPlayerName(id) + "从牌堆里摸了"
				+ packet.getCardVOs().length + "张牌");

		//System.out.println("drawPhase++++" + id + " " + playerId);
		
		if (id != playerId) {	// 别的玩家
			OtherPlayerPane pane = owner.getOtherPlayerPaneList().get(owner
					.getIndex(id));
			// 更新该玩家面板上的牌数
			pane.setHandCardCount(packet.getHandCardCount());
			pane.repaint();

		} else {	// 自己
			for (CardVO vo : packet.getCardVOs()) {
				//AbstractCard card = AbstractCard.createCard(vo);
				AbstractCard card = vo.toCard();
				// 新牌加入手牌
				players[playerId].addHandCard(card);
				// 更新自己的面板
				owner.getDashboard().addHandCard(card);
			}
			// 直接返回摸牌结束
			send(new SGSPacket(Opercation.OP_PHASE_DRAW_END));
		}
	}

	public String getPlayerName(int id) {
		if (id != playerId) {
			return players[id].getCharacterName();
		} else {
			return players[id].getCharacterName() + "(你)";
		}
	}

	/**
	 * 出牌阶段 -> OP_PHASE_PLAY_BEGIN
	 * @param id
	 */
	public void playPhase(int id) {
		// 游戏日志
		owner.showMessage(getPlayerName(id) + "进入出牌阶段");
		// 改变该ID玩家的阶段
		players[id].setPhase(Phase.PLAY);

		if (id != playerId) { // 不是自己
			// 更新其他玩家面板
			owner.getOtherPlayerPaneList().get(owner.getIndex(id)).repaint();
		} else {
			// 设置状态
			//gameFrame.getDashboard().setHasOffedSha(false);
			owner.getDashboard().setCancelable(true);
			// 调用钩子函数
			owner.getDashboard().phaseChangeHook(Phase.PLAY);
			// 没有发送消息给服务器，一直等待玩家出牌
		}
	}

	/**
	 * 发送离线请求
	 */
	public void offline() {
		SGSPacket packet = new SGSPacket(Opercation.OP_OFFLINE);
		packet.setPlayerId(playerId);
		send(packet);
	}

	/**
	 * 向对手出牌
	 * 
	 * @param card
	 *            出牌
	 * @param toId
	 *            对手id
	 */
	public void sendOfferCardToInfo(AbstractCard card, int toId) {
		SGSPacket packet = new SGSPacket(Opercation.OP_OFFER_CARD_TO);
		
		// 存储已经发出
		//owner.setSendedCard(card);
		owner.setSendCardInfo(toId, card);
		
		packet.setCardVO(card.toCardVO());
		packet.setPlayerId(playerId);
		packet.setToPlayerId(toId);
		
		players[playerId].removeHandCard(card);
		players[playerId].setPhase(Phase.WAIT_OTHER);
		owner.getDashboard().repaint();
		send(packet);
	}

	/**
	 * 对别人出牌给予回应 -> OP_OFFER_CARD_TO
	 * @param packet
	 */
	public void beOfferredCardTo(SGSPacket packet) {
//		AbstractCard card = AbstractCard.createCard(packet.getCardVO());
		AbstractCard card = packet.getCardVO().toCard();
		int fromId = packet.getPlayerId();
		int toId = packet.getToPlayerId();
		// 游戏日志
		String message = getPlayerName(fromId) + "向"
				+ getPlayerName(toId) + "出牌《"
				+ card.getName() + "》";
		owner.showMessage(message);

		// 其他玩家对自己出牌
		if (packet.getToPlayerId() == playerId) {
			//owner.setBeOfferedCard(card);
			//owner.setCardFromId(packet.getPlayerId());
			owner.setBeOfferedCardInfo(fromId, card);
			owner.changeCurrentPlayerPhase(Phase.FEEDBACK);
			owner.showMessageKeep(message);
		}
		// 所有玩家的台面上出现弃牌
		owner.addDiscardedCard(card, getPlayerName(fromId)
				+ "出牌");
		players[packet.getPlayerId()].removeHandCard(card);

		for (OtherPlayerPane pane : owner.getOtherPlayerPaneList()) {

			if (pane.getPlayer().getPlayerId() == toId) {
				pane.setSelected(true);

			} else if (pane.getPlayer().getPlayerId() == fromId) {
				pane.showEffect(card);
			}
		}
	}
	
	public void sendFeedbackInfo(AbstractCard cardToFeedback) {
		SGSPacket packet = new SGSPacket(Opercation.OP_FEEDBACK);
		if (cardToFeedback != null) {
//			CardVO cardVO = new CardVO(cardToFeedback);
			CardVO cardVO = cardToFeedback.toCardVO();
			packet.setCardVO(cardVO);
		}
		packet.setPlayerId(playerId);
		packet.setToPlayerId(owner.getCardFromId());
		send(packet);
	}

	/**
	 * 回应别人出的牌 -> OP_FEEDBACK
	 * @param packet
	 */
	public void feedback(SGSPacket packet) {
		
		int fromId = packet.getPlayerId();
//		int toId = packet.getToPlayerId();
		
		if (packet.getCardVO() != null) {
			//AbstractCard card = AbstractCard.createCard(packet.getCardVO());
			AbstractCard card = packet.getCardVO().toCard();
			//if (card.getName().equals("闪")) {
				owner.addDiscardedCard(card,
						players[fromId].getName() + "出《" + card.getName() + "》");
				players[fromId].removeHandCard(card);

				if (packet.getPlayerId() == playerId) {
					owner.getDashboard().showEffect(card);

				} else {
					owner.getOtherPlayerPaneList().get(
							owner.getIndex(packet.getPlayerId()))
							.showEffect(card);
				}
			//}
		} else {
			Phase phase = owner.getCurrentPlayer().getPhase();
			if (phase.equals(Phase.WAIT_OTHER)) {
				owner.getDispatchInfo().cardHitsTarget();
			}
		}
		if (packet.getPlayerId() == playerId) {
			players[playerId].setPhase(Phase.NOT_ACTIVE);
			owner.getDashboard().repaint();

		} else if (packet.getToPlayerId() == playerId) {
//			players[playerId].setPhase(Phase.PLAY);
//			gameFrame.getDashboard().repaint();
			owner.changeCurrentPlayerPhase(Phase.PLAY);
		}
	}

	public void sendDecreaseLifeInfo(int playerId, int num) {
		SGSPacket packet = new SGSPacket(Opercation.OP_DECREASE_LIFE);
		packet.setPlayerId(playerId);
		// TODO: 没有少血的数量
		send(packet);
	}

	public void decreaseLife(SGSPacket packet) {
		// players[packet.getPlayerId()].getCharacter().decreaseLife();
		owner.decreaseLife(packet.getPlayerId());
	}

	public void sendAddEquipmentInfo(AbstractEquipmentCard equipmentCard,
			AbstractEquipmentCard cardToRemove) {
		SGSPacket packet = new SGSPacket(Opercation.OP_ADD_EQUIPMENT);
		packet.setPlayerId(playerId);
//		packet.setCardVO(new CardVO(equipmentCard));
		packet.setCardVO(equipmentCard.toCardVO());
		if (cardToRemove != null) {
//			packet.setAnotherCardVO(new CardVO(cardToRemove));
			packet.setAnotherCardVO(cardToRemove.toCardVO());
		}
		send(packet);
	}

	/**
	 * 出牌结束
	 */
	public void sendEndPlayInfo() {
		SGSPacket packet = new SGSPacket(Opercation.OP_PHASE_PLAY_END);
		packet.setPlayerId(playerId);
		send(packet);
	}

	/**
	 * 弃牌阶段 -> OP_PHASE_DISCARD_BEGIN
	 * @param packet
	 */
	public void discard(SGSPacket packet) {
		int thePlayer = packet.getPlayerId();
		String message = getPlayerName(thePlayer) + "进入弃牌阶段";
		owner.showMessage(message);
		
		if (thePlayer == playerId) {
			//if (!players[playerId].needToDiscard()) {
				//endDiscard();
			//} else {
				owner.discard();
			//}
			owner.changeCurrentPlayerPhase(Phase.DISCARD);
		} else {
			players[thePlayer].setPhase(Phase.DISCARD);
		}
	}

//	/**
//	 * 弃牌结束
//	 */
//	public void endDiscard() {
//		discardCards(new ArrayList<AbstractCard>());
//	}

	/**
	 * 弃一组牌
	 * 
	 * @param cardList
	 */
	public void discardCards(List<AbstractCard> cardList) {
		CardVO[] cardVOs = new CardVO[cardList.size()];
		int index = 0;
		for (AbstractCard card : cardList) {
			cardVOs[index++] = card.toCardVO();
		}
		SGSPacket packet = new SGSPacket(Opercation.OP_DISCARD);
		packet.setCardVOs(cardVOs);
		packet.setPlayerId(playerId);
		send(packet);
	}

	/**
	 * 弃牌结束
	 * 
	 * @param packet
	 */
	public void discardEnd(SGSPacket packet) {
		int discardId = packet.getPlayerId(); 
		for (CardVO cardVO : packet.getCardVOs()) {
			//AbstractCard card = AbstractCard.createCard(cardVO);
			AbstractCard card = cardVO.toCard();
			owner.addDiscardedCard(card,
					getPlayerName(discardId) + "弃牌");
			// 玩家弃牌
			players[discardId].getHandCards().remove(card);
		}
		players[discardId].setPhase(Phase.NOT_ACTIVE);

		if (packet.getPlayerId() == playerId) {
			owner.getDashboard().repaint();
		} else {
			owner.getOtherPlayerPaneList().get(
					owner.getIndex(packet.getPlayerId())).repaint();
		}
	}

	public void useHandCard(AbstractCard card) {
		if (card.getName().equals("桃")) {
			SGSPacket packet = new SGSPacket(Opercation.OP_EAT_PEACH);
			packet.setPlayerId(playerId);
//			packet.setCardVO(new CardVO(card));
			packet.setCardVO(card.toCardVO());
			send(packet);
		}
	}

	/**
	 * 吃桃 -> OP_EAT_PEACH
	 * @param packet
	 */
	public void eatPeach(SGSPacket packet) {
		players[packet.getPlayerId()].getCharacter().increaseLife();
		//AbstractCard card = AbstractCard.createCard(packet.getCardVO());
		AbstractCard card = packet.getCardVO().toCard();
		players[packet.getPlayerId()].removeHandCard(card);

		if (packet.getPlayerId() == playerId) {
			owner.getDashboard().repaint();
			owner.getDashboard().showEffect(card);

		} else {
			owner.getOtherPlayerPaneList().get(
					owner.getIndex(packet.getPlayerId())).repaint();
			owner.getOtherPlayerPaneList().get(
					owner.getIndex(packet.getPlayerId())).showEffect(card);
		}
	}

	/**
	 * 装上装备牌 -> OP_ADD_EQUIPMENT
	 * @param packet
	 */
	public void addEquipmentCard(SGSPacket packet) {
//		AbstractEquipmentCard card = (AbstractEquipmentCard) AbstractCard.createCard(packet
//				.getCardVO());
		AbstractCard card = packet.getCardVO().toCard();
		owner.showMessage(getPlayerName(packet.getPlayerId()) + "装备了"
				+ card.getName());
		players[packet.getPlayerId()].removeHandCard(card);

		if (packet.getAnotherCardVO() != null) {
			owner.addDiscardedCard(
					packet.getAnotherCardVO().toCard(),
					getPlayerName(packet.getPlayerId()) + "卸掉装备牌");
		}

		if (packet.getPlayerId() == playerId) {
//			gameFrame.getDashboard().addEquipmentCard(card);

		} else {
//			gameFrame.getOtherPlayerPaneList().get(
//					gameFrame.getIndex(packet.getPlayerId())).addEquipmentCard(
//					card);
		}
	}
}
